import {
  getDefaultHeaders,
  setContextType,
  setUserStatusResponse,
  initAppInfo
} from './request-fetch'
import qs from 'qs'

function transformBody (option, body) {
  if (['GET', 'HEAD'].includes(option?.method)) {
    return `${qs.stringify(body)}`
  }
  if (option.headers?.get('content-type')?.includes('application/json')) {
    return JSON.stringify(body)
  }
  if (option.headers?.get('content-type')?.includes('application/x-www-form-urlencoded')) {
    return qs.stringify(body)
  }
  return body
}

const transformResponse = async (type, text) => {
  let data
  try {
    if (type === 'json' || type === '') {
      data = JSON.parse(text)
    } else {
      data = text
    }
  } catch (e) {
    return data
  }
  return data
}

const getResponseHeaders = (xhr) => {
  const headers = new Headers()
  xhr
    .getAllResponseHeaders()
    .split('\r\n')
    .forEach((line) => {
      if (line) {
        const [key, value] = line.split(':')
        headers.append(key, value)
      }
    })
  return headers
}

function fetchReqeust (method, url, data, option) {
  return new Promise((resolve) => {
    let options = {}
    if (option) options = option
    const headers = getDefaultHeaders(options)
    options.headers = headers
    options.method = method
    setContextType(options)

    if (['GET', 'HEAD'].includes(method)) {
      url = `${url}?${transformBody(options, data)}`
    } else {
      options.body = transformBody(options, data)
    }
    const xhr = new XMLHttpRequest()
    xhr.open(method, url)
    if (options.process) {
      xhr.upload.addEventListener('progress', options.process)
    }
    for (const [key, value] of options?.headers.entries()) {
      xhr.setRequestHeader(key, value)
    }
    xhr.onreadystatechange = function () {
      if (xhr.readyState === 4) {
        resolve({
          status: xhr.status,
          type: xhr.responseType,
          res: xhr.responseText,
          headers: getResponseHeaders(xhr)
        })
      }
    }
    xhr.send(options.body)
  })
}

export async function requestXhr (
  method,
  url,
  data,
  option
) {
  await initAppInfo()
  const { status, res, headers, type } = await fetchReqeust(method, url, data, option)
  const statusCode = status
  const json = await transformResponse(type, res)
  setUserStatusResponse(statusCode, json)
  return { error: null, data: json, header: headers, statusCode }
}
